<?php
/**
 * @Author: feidao@ibantang.com, 2019, all rights reserved update by jiji
 * @Date: 2019-05-31
 * @Time: 15:51
 * @Brief:
 */

namespace Core\Common\Model;

use Core\Common\Route\Request;
use Core\Common\Util\DbError;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Database\Connectors\ConnectionFactory as CF;
use Illuminate\Support\Arr;

class ConnectionFactory extends CF
{
    /**
     * Create a new Closure that resolves to a PDO instance with a specific host or an array of hosts.
     *
     * @param array $config
     * @return \Closure
     */
    protected function createPdoResolverWithHosts(array $config)
    {
        return function () use ($config) {
            $hosts = [];
            if (Request::isRunningInMars()) {
                $marsHost = $config["mars_mock_host"] ?? "";
                if (!empty($marsHost)) {
                    $hosts = explode(",", $marsHost);
                    $config['port'] = intval($config["mars_mock_port"] ?? 3306);
                    $config['username'] = $config["mars_mock_username"] ?? '';
                    $config['password'] = $config["mars_mock_password"] ?? '';
                }
            } else {
                $hosts = Arr::shuffle($this->parseHosts($config));
                // 优先使用连接池，如果连接池有问题则按之前的主从逻辑处理
                if (defined("DISABLE_DB_CONNECTION_POOL") && "1" == DISABLE_DB_CONNECTION_POOL) {
                    // 不使用连接池
                } else {
                    $poolHost = $config["pool_host"] ?? "";
                    $poolHost = trim($poolHost);
                    if (!empty($poolHost)) {
                        $arrPoolHost = explode(",", $poolHost);
                        foreach ($arrPoolHost as $tmpHost) {
                            if (empty(trim($tmpHost))) {
                                continue;
                            }
                            array_unshift($hosts, trim($tmpHost));
                        }
                    }
                }
            }
            $tryHosts = [];
            foreach ($hosts as $key => $host) {
                $config["host"] = $host;
                try {
                    return $this->createConnector($config)->connect($config);
                } catch (\PDOException $e) {
                    $tryHosts[] = $host;
                    $errMsg = $e->getMessage();
                    if (DbError::causedByLostConnection($errMsg)) {
                        continue;
                    }
                    if (count($hosts) - 1 === $key && $this->container->bound(ExceptionHandler::class)) {
                        $this->container->make(ExceptionHandler::class)->report($e);
                    }
                    throw $e;
                }
            }
            $errMsg = sprintf("connect to mysql error, try %d times, hosts:%s", count($tryHosts), implode(",", $tryHosts));
            throw new \Exception($errMsg, 501001);
        };
    }
}
